﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using MangaGrr.DomainModel;
using MangaGrr.Logic;
using MinhUtils;
using System.Threading;
using MangaGrr.MgrEventArgs;

namespace MangaGrr
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();

            MGRUtil.AllowUnsafeHeaderParsing();
            txtFolderToSave.Text = MangaGrr.Properties.Settings.Default.SaveTo;

            //load and show list of manga sources (from db)
            LoadMangaSite();

            //load and show list of manga of currently selected manga source (from db)
            LoadMangaFromDatabase();
            
            //load and save (to memory/db) list manga of each manga source (from site) (using multi-thread)
            //LoadMangaFromSite();

            //load and show total mangaChapter of showing mangas (from site) (using multi-thread)
            LoadChapterFromSite();

            //set event handlers on combo boxes
            //reason of setting this at the end is to prevent threads from invoke ontrols before they are fully initialized
            cbxMangaSite.SelectedIndexChanged += cbxMangaSite_SelectedIndexChanged;
        }

        private readonly int TOTAL_CHAPTER_LOADING_THREAD = 3;
        private Mutex _mutex1 = new Mutex();
        private Queue<int> _queue1 = new Queue<int>();

        /// <summary>
        /// load and show total mangaChapter of showing mangas (from site) (using multi-thread)
        /// </summary>
        private void LoadChapterFromSite()
        {
            int columnIndex = dgvManga.Columns["MangaTotalChapter"].Index;
            int columnIndex2 = dgvManga.Columns["MangaID"].Index;

            //TODO only 1 thread starts, check again
            for(int i = 0; i < TOTAL_CHAPTER_LOADING_THREAD; i++)
            {
                new Thread(new ThreadStart(delegate()
                    {
                        while (true) //TODO change this so thread is terminated when finishing loading or when form is closed
                        {
                            try
                            {
                                _mutex1.WaitOne();
                                int rowIndex = _queue1.Dequeue();
                                _mutex1.ReleaseMutex();

                                dgvManga[columnIndex, rowIndex].Value = "Loading";
                                string mangaURL = dgvManga[columnIndex2, rowIndex].Value.ToString();

                                Manga manga = MGRDataAccessor.GetMangaByURL(mangaURL);
                                MangaDownloader mangaLogic = new MangaDownloader(manga);
                                int totalChapter = mangaLogic.LoadChapter().Count;

                                dgvManga[columnIndex, rowIndex].Value = totalChapter.ToString();
                            }
                            catch
                            {
                            }

                            Thread.Sleep(500);
                        }
                    })).Start();
            }
        }

        /// <summary>
        /// load and show list of manga of currently selected manga source (from db)
        /// </summary>
        private void LoadMangaFromDatabase()
        {
            MangaSite mangaSite = (MangaSite)cbxMangaSite.SelectedItem;

            try
            {
                FormUtil.SetLink(llbOpenMangaSiteURL, mangaSite.MangaListURL);

                FormUtil.EnableControl(cbxMangaSite, false);
                lblMangaCount.Text = "Loading...";
                _mutex1.WaitOne();
                _queue1.Clear();
                _mutex1.ReleaseMutex();
                dgvManga.Rows.Clear();

                new Thread(new ThreadStart(delegate()
                {
                    ICollection<Manga> savedMangaList = MGRDataAccessor.GetMangaList(mangaSite);

                    DataTable dtManga = new DataTable();
                    dtManga.Columns.Add("ID");
                    dtManga.Columns.Add("Manga");
                    dtManga.Columns.Add("Site");
                    dtManga.Columns.Add("Total Chapter");
                    
                    int i = 0;
                    foreach (Manga manga in savedMangaList)
                    {
                        Action<Manga> addManga = AddMangaToDataGridView;
                        Invoke(addManga, new object[] { manga });
                        _queue1.Enqueue(i++);
                    }

                    Action<Label, string> setLabelText = FormUtil.SetLabelText;
                    Invoke(setLabelText, new object[] { this.lblMangaCount, savedMangaList.Count.ToString() });

                    Action<Control, bool> enableControl = FormUtil.EnableControl;
                    Invoke(enableControl, new object[] { this.cbxMangaSite, true });
                })).Start();
            }
            catch (Exception ex)
            {
                MGRUtil.WriteLog("Exception caught while loading manga from " + mangaSite.Name + ": " + ex.ToString());
                Thread.CurrentThread.Abort();
            }
        }

        private void AddMangaToDataGridView(Manga manga)
        {
            DataGridViewRow newRow = dgvManga.Rows[dgvManga.Rows.Add()];

            newRow.Cells["MangaID"].Value = manga.URL;
            newRow.Cells["MangaName"].Value = manga.Name;
            newRow.Cells["MangaSite"].Value = manga.MangaSite.Name;
            newRow.Cells["MangaTotalChapter"].Value = "-";
        }

        /// <summary>
        /// load and show list of manga sources (from db)
        /// </summary>
        private void LoadMangaSite()
        {
            cbxMangaSite.Items.Clear();
            cbxMangaSite.DisplayMember = "Name";

            ICollection<MangaSite> mangaSiteCol = MGRDataAccessor.GetMangaSiteList();

            //_totalMangaSite = mangaSiteCol.Count;

            for (int i = 0; i < mangaSiteCol.Count; i++)
            {
                MangaSite mangaSite = mangaSiteCol.ElementAt(i);
                cbxMangaSite.Items.Add(mangaSite);
            }

            if (cbxMangaSite.Items.Count > 0) //select first item
                cbxMangaSite.SelectedIndex = 0;
        }

        private void cbxMangaSite_SelectedIndexChanged(object sender, EventArgs e)
        {
            LoadMangaFromDatabase();
        }

        private void dgvManga_SelectionChanged(object sender, EventArgs e)
        {
            
        }

        private void dgvManga_CellContentClick(object sender, DataGridViewCellEventArgs e)
        {
            //TODO change to a better event (row selected)
            //TODO show loading effect (not working now)

            string mangaURL = dgvManga[dgvManga.Columns["MangaID"].Index, e.RowIndex].Value.ToString();

            //show list of mangaChapter of currently selected manga
            Manga manga = MGRDataAccessor.GetMangaByURL(mangaURL);//(Manga)cbxManga.SelectedItem;
            FormUtil.SetLink(llbOpenMangaUrl, manga.URL);

            Action<object, bool> showChapterLoadingEffect = delegate(object sender2, bool show)
            {
                if (sender2 == cbxManga.SelectedItem)
                {
                    pbxChapterLoading.Visible = show;
                    //cbxMangaSite.Enabled = !show;
                    //cbxManga.Enabled = !show;
                }
            };

            Action<object, ICollection<MangaChapter>> showChapters = delegate(object sender2, ICollection<MangaChapter> chapterCol)
            {
                //load list of chapters from selected manga
                if (sender2 == cbxManga.SelectedItem || true)
                {
                    clbChapter.Items.Clear();
                    clbChapter.DisplayMember = "DisplayName";
                    clbChapter.Items.AddRange(chapterCol.ToArray());

                    cbxFromChapter.Items.Clear();
                    cbxFromChapter.DisplayMember = "OrderInfo";
                    cbxFromChapter.Items.AddRange(chapterCol.ToArray());
                    if (cbxFromChapter.Items.Count > 0)
                        cbxFromChapter.SelectedIndex = 0;

                    FormUtil.CheckAll(clbChapter, true);

                    lblChapterCount.Text = cbxFromChapter.Items.Count.ToString();
                }
            };

            Thread loadChapterThread = new Thread(delegate()
            {
                Invoke(showChapterLoadingEffect, new object[] { manga, true });

                var mangaLogic = new MangaDownloader(manga);

                ICollection<MangaChapter> chapterCol = mangaLogic.LoadChapter();

                Invoke(showChapters, new object[] { manga, chapterCol });

                Invoke(showChapterLoadingEffect, new object[] { manga, false });
            });

            loadChapterThread.IsBackground = true;
            loadChapterThread.Start();
        }

        private void btnQueueSelected_Click(object sender, EventArgs e)
        {
            QueueSelected();
        }


        /// <summary>
        /// Add all currently checked chapters to queue
        /// </summary>
        private void QueueSelected()
        {
            if (clbChapter.CheckedItems.Count > 0) //if there're chapters checked in mangaChapter list
            {
                foreach (MangaChapter chapter in clbChapter.CheckedItems)
                {
                    //_chapterQueue.Add(mangaChapter); //ignore duplication
                    AddChapterToQueue(chapter);
                }

                //btnQueueSelected.Text = "Add to Queue [" + _chapterQueue.Count + "]";
                //btnClearQueue.Enabled = true;

                FormUtil.UncheckAll(clbChapter);
            }
            else
            {
                MessageBox.Show("No mangaChapter is checked.");
            }
        }

        private void AddChapterToQueue(MangaChapter mangaChapter)
        {
            DataGridViewRow newRow = dgvQueue.Rows[dgvQueue.Rows.Add()];

            newRow.Cells["QueueID"].Value = mangaChapter.URL;
            newRow.Cells["QueueChapter"].Value = mangaChapter.OrderInfo;
            newRow.Cells["QueueManga"].Value = mangaChapter.Manga.Name;
            newRow.Cells["QueueSite"].Value = mangaChapter.Manga.MangaSite.Name;
            newRow.Cells["QueueStatus"].Value = "Waiting";

            _colMangaChapterDownloaders.Add(new MangaChapterDownloader(mangaChapter));
        }

        private readonly ICollection<MangaChapterDownloader> _colMangaChapterDownloaders = new List<MangaChapterDownloader>();
        private MgrDownloader _downloader = null;
        private void btnDownload_Click(object sender, EventArgs e)
        {
            lblPercentage.Text = "Initializing";

            pbrDownload.Minimum = 0;
            pbrDownload.Maximum = 100;

            _downloader = new MgrDownloader();
            _downloader.DownloadProgressChanged += _downloader_DownloadProgressChanged;
            _downloader.DownloadCompleted += _downloader_DownloadCompleted;

            _downloader.StartDownloading(_colMangaChapterDownloaders, txtFolderToSave.Text);
        }

        private void _downloader_DownloadCompleted(object sender, EventArgs e)
        {
            Action disposer = delegate()
            {
                try
                {
                    this.Close();
                }
                catch { }
            };
            Invoke(disposer);
        }

        private void _downloader_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
        {
            try
            {
                Action<DownloadProgressChangedEventArgs> showProgress = ShowProgress;
                Invoke(showProgress, new object[] { e });
            }
            catch { }
        }

        private void ShowProgress(DownloadProgressChangedEventArgs e)
        {
            try
            {
                this.Text = e.PercentCompleted + "%";

                lblEclapsed.Text = StringUtil.ToHHMMSS(e.TimeEclapsed);
                lblTimeLeft.Text = StringUtil.ToHHMMSS(e.TimeLeft);
                lblPercentage.Text = e.PercentCompleted + "%";
                pbrDownload.Value = (int)e.PercentCompleted;
                //lblFetchDownloadStatus.Text = "F" + e.TotalFetchingThreads + " D" + e.TotalDownloadingThreads;
            }
            catch { }
        }
    }
}
